package com.symaster.common.geom.entity;

import com.symaster.common.geom.util.PointUtil;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;

/**
 * 轮廓上的线段
 */
public class LineSegment implements Serializable, Cloneable {
    private final String uid;
    private Color color;
    private Point startPoint;         // 第一个点
    private Point endPoint;           // 第二个点
    private LineSegment next;         // 其连接的下一条线段，即next边的一个点与当前线段的一个点相同

    public LineSegment(Point startPoint, Point endPoint) {
        this.startPoint = startPoint;
        this.endPoint = endPoint;
        this.next = null;
        this.uid = UUID.randomUUID().toString();
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    /**
     * 判断给定点是否在此线段上
     */
    public boolean onSegment(Point point) {
        return ((point.x - startPoint.x) * (endPoint.y - startPoint.y) == (endPoint.x - startPoint.x) * (point.y - startPoint.y) && Math.min(startPoint.x, endPoint.x) <= point.x && point.x <= Math.max(startPoint.x, endPoint.x) && Math.min(startPoint.y, endPoint.y) <= point.y && point.y <= Math.max(startPoint.y, endPoint.y));
    }

    /**
     * 平移
     */
    public void translate(Vector vector) {
        translate(vector.getX(), vector.getY());
    }

    /**
     * 平移
     */
    public void translate(double xn, double yn) {

        startPoint.setY(startPoint.getY() + yn);
        startPoint.setX(startPoint.getX() + xn);
        endPoint.setY(endPoint.getY() + yn);
        endPoint.setX(endPoint.getX() + xn);
    }

    /**
     * 移动线条至指定坐标
     * 以'startPoint'为准
     */
    public void move(double x, double y) {
        Rectangle2D.Double round = round();
        Vector translateVector = PointUtil.getTranslateVector(round.getX(), round.getY(), x, y);
        translate(translateVector);
    }

    public void scale(double scale) {
        if (startPoint == null || endPoint == null) {
            return;
        }
        startPoint.x = startPoint.x * scale;
        startPoint.y = startPoint.y * scale;

        endPoint.x = endPoint.x * scale;
        endPoint.y = endPoint.y * scale;
    }

    public double length() {
        return PointUtil.dis(startPoint, endPoint);
    }

    public Rectangle2D.Double round() {
        double x = startPoint.getX();
        double x1 = endPoint.getX();
        double min = Math.min(x, x1);
        double maxX = Math.max(x, x1);

        double y = startPoint.getY();
        double y1 = endPoint.getY();
        double minY = Math.min(y, y1);
        double maxY = Math.max(y, y1);

        return new Rectangle2D.Double(min, minY, (maxX - min), (maxY - minY));
    }

    public Point center() {
        Rectangle2D.Double round = round();
        return new Point(round.getCenterX(), round.getCenterY());
    }

    public LineSegment getNext() {
        return next;
    }

    public void setNext(LineSegment next) {
        this.next = next;
    }

    public void rotate(Point center, double angle) {
        double angleInRadians = (angle * Math.PI / 180);
        AffineTransform rotateInstance = AffineTransform.getRotateInstance(angleInRadians, center.getX(), center.getY());

        double[] c1 = new double[]{startPoint.getX(), startPoint.getY()};
        double[] c2 = new double[]{endPoint.getX(), endPoint.getY()};
        double[] o1 = new double[2];
        double[] o2 = new double[2];
        rotateInstance.transform(c1, 0, o1, 0, 1);
        rotateInstance.transform(c2, 0, o2, 0, 1);
        startPoint.setX(o1[0]);
        startPoint.setY(o1[1]);
        endPoint.setX(o2[0]);
        endPoint.setY(o2[1]);
    }

    public Point getStartPoint() {
        return startPoint;
    }

    public void setStartPoint(Point startPoint) {
        this.startPoint = startPoint;
    }

    public Point getEndPoint() {
        return endPoint;
    }

    public void setEndPoint(Point endPoint) {
        this.endPoint = endPoint;
    }

    /**
     * point 是否为该线段的端点
     */
    public boolean isEndPoint(Point point) {
        return this.startPoint.equals(point) || this.endPoint.equals(point);
    }

    @Override
    public int hashCode() {
        return Objects.hash(uid);
    }

    @Override
    public String toString() {
        return "LineSegment{" +
                "startPoint=" + startPoint +
                ", endPoint=" + endPoint +
                '}';
    }

    @Override
    public LineSegment clone() {
        try {
            return (LineSegment) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
